/*
 * ESPRESSIF MIT License
 *
 * Copyright (c) 2021 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
 *
 * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
 * it is free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include "driver/i2c.h"
#include "i2c_bus.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/task.h"
#include "board.h"


#define GT911_CHIP_ADDR_DEFAULT   (0x28)

//#define GT911_CHIP_ADDR_DEFAULT   (0x24)
#define ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS (0x5D) // 0xBA/BB
#define ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP (0x14) // 0x28/29

/* GT911 registers */
#define ESP_LCD_TOUCH_GT911_READ_KEY_REG    (0x8093)
#define ESP_LCD_TOUCH_GT911_READ_XY_REG     (0x814E)
#define ESP_LCD_TOUCH_GT911_CONFIG_REG      (0x8047)
#define ESP_LCD_TOUCH_GT911_PRODUCT_ID_REG  (0x8140)
#define ESP_LCD_TOUCH_GT911_ENTER_SLEEP     (0x8040)

/* GT911 support key num */
#define ESP_GT911_TOUCH_MAX_BUTTONS         (4)


static const char *TAG = "GT911";

static uint8_t tp_num, btn_val;
static uint16_t x, y, btn_signal;
static i2c_bus_handle_t i2c_handle;

static esp_err_t gt911_read(uint8_t *data, size_t data_len)
{
    esp_err_t ret_val = ESP_OK;
    static uint8_t reg_addr=GT911_CHIP_ADDR_DEFAULT;
    ret_val = i2c_bus_read_bytes(i2c_handle,GT911_CHIP_ADDR_DEFAULT, &reg_addr, sizeof(reg_addr), data, data_len);
    return ret_val;
}

static int i2c_init()
{
    int res = 0;
    i2c_config_t i2c_pin = { 0 };
    res = get_i2c_pins(I2C_NUM_0, &i2c_pin);
    if (res != 0) {
        ESP_LOGE(TAG, "get i2c pins error");
        return res;
    }
    i2c_config_t es_i2c_cfg = {
        .mode = I2C_MODE_MASTER,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 100000,
        .sda_io_num = i2c_pin.sda_io_num,
        .scl_io_num = i2c_pin.scl_io_num,
    };
    i2c_handle = i2c_bus_create(I2C_NUM_0, &es_i2c_cfg);
    if (i2c_handle == NULL) {
        ESP_LOGE(TAG, "i2c_bus_create error");
        return -1;
    }
    return 0;
}

esp_err_t gt911_tp_init(void)
{
    esp_err_t ret_val = i2c_init();

    uint16_t reg_val = 0;
    uint8_t buf[8]={0};

    static uint8_t reg_addr[2];
	reg_addr[0]=ESP_LCD_TOUCH_GT911_PRODUCT_ID_REG>>8;
	reg_addr[1]=ESP_LCD_TOUCH_GT911_PRODUCT_ID_REG;
    uint8_t data;
    ret_val = i2c_bus_read_bytes(i2c_handle,GT911_CHIP_ADDR_DEFAULT,reg_addr, sizeof(reg_addr),  (uint8_t *)&buf[0], 3);
    reg_addr[0]=ESP_LCD_TOUCH_GT911_CONFIG_REG>>8;
	reg_addr[1]=ESP_LCD_TOUCH_GT911_CONFIG_REG;
    ret_val = i2c_bus_read_bytes(i2c_handle,GT911_CHIP_ADDR_DEFAULT, reg_addr, sizeof(reg_addr),  (uint8_t *)&buf[3], 1);
    ESP_LOGI(TAG, "TouchPad_ID:0x%02x,0x%02x,0x%02x", buf[0], buf[1], buf[2]);
    ESP_LOGI(TAG, "TouchPad_Config_Version:%d", buf[3]);
/*    
    do {
        gt911_read((uint8_t *)&reg_val, sizeof(uint16_t));
        vTaskDelay(pdMS_TO_TICKS(20));
    } while ((reg_val != 0x0002) && ((reg_val & 0xFF00) != 0xFF00)) ;
    */
    return ret_val;
    
}

esp_err_t gt911_tp_read(void)
{
    esp_err_t err = ESP_OK;
    uint8_t buf[41];
    uint8_t touch_cnt = 0;
    uint8_t clear = 0;
    size_t i = 0;
    static uint8_t reg_addr[2];// = ESP_LCD_TOUCH_GT911_READ_XY_REG;
	reg_addr[0]=ESP_LCD_TOUCH_GT911_READ_XY_REG>>8;
	reg_addr[1]=ESP_LCD_TOUCH_GT911_READ_XY_REG;
    err = i2c_bus_read_bytes(i2c_handle, GT911_CHIP_ADDR_DEFAULT,reg_addr,sizeof(reg_addr), buf, 1);
    //ESP_LOGI(TAG, "[0] d0=%x,d1=%x,d2=%x,d3=%x,d4=%x",buf[0],buf[1],buf[2],buf[3],buf[4]);
    if ((buf[0] & 0x80) == 0x00) {
        //reg_addr = ESP_LCD_TOUCH_GT911_READ_XY_REG;
		reg_addr[0]=ESP_LCD_TOUCH_GT911_READ_XY_REG>>8;
		reg_addr[1]=ESP_LCD_TOUCH_GT911_READ_XY_REG;
        err = i2c_bus_write_bytes(i2c_handle, GT911_CHIP_ADDR_DEFAULT,reg_addr,sizeof(reg_addr), &clear, 1);
		//ESP_LOGI(TAG, "[1] clear d0=%x,d1=%x,d2=%x,d3=%x,d4=%x",buf[0],buf[1],buf[2],buf[3],buf[4]);
    	
    } else if ((buf[0] & 0x10) == 0x10) {
        /* Read all keys */
        uint8_t key_max = ESP_GT911_TOUCH_MAX_BUTTONS;
        //reg_addr = ESP_LCD_TOUCH_GT911_READ_KEY_REG;
		reg_addr[0]=ESP_LCD_TOUCH_GT911_READ_KEY_REG>>8;
		reg_addr[1]=ESP_LCD_TOUCH_GT911_READ_KEY_REG;
        err = i2c_bus_read_bytes(i2c_handle, GT911_CHIP_ADDR_DEFAULT,reg_addr,sizeof(reg_addr), &buf[0], key_max);
        //ESP_LOGI(TAG, "[2] d0=%x,d1=%x,d2=%x,d3=%x,d4=%x",buf[0],buf[1],buf[2],buf[3],buf[4]);
    	/* Clear all */
        
        err = i2c_bus_write_bytes(i2c_handle, GT911_CHIP_ADDR_DEFAULT,reg_addr,sizeof(reg_addr), &clear, 1);
		//ESP_LOGI(TAG, "[3] clear d0=%x,d1=%x,d2=%x,d3=%x,d4=%x",buf[0],buf[1],buf[2],buf[3],buf[4]);
			

    } else if ((buf[0] & 0x80) == 0x80) {
        /* Count of touched points */
        touch_cnt = buf[0] & 0x0f;
        if (touch_cnt > 5 || touch_cnt == 0) {
        
            //reg_addr = ESP_LCD_TOUCH_GT911_READ_XY_REG;
			reg_addr[0]=ESP_LCD_TOUCH_GT911_READ_KEY_REG>>8;
			reg_addr[1]=ESP_LCD_TOUCH_GT911_READ_KEY_REG;
            err = i2c_bus_write_bytes(i2c_handle, GT911_CHIP_ADDR_DEFAULT,reg_addr,sizeof(reg_addr), &clear, 1);
			//ESP_LOGI(TAG, "[4] clear d0=%x,d1=%x,d2=%x,d3=%x,d4=%x",buf[0],buf[1],buf[2],buf[3],buf[4]);
			return ESP_OK;
        }

        /* Read all points */
        
        //reg_addr = ESP_LCD_TOUCH_GT911_READ_XY_REG;
		reg_addr[0]=ESP_LCD_TOUCH_GT911_READ_XY_REG>>8;
		reg_addr[1]=ESP_LCD_TOUCH_GT911_READ_XY_REG+1;
        err = i2c_bus_read_bytes(i2c_handle, GT911_CHIP_ADDR_DEFAULT,reg_addr,sizeof(reg_addr), &buf[1], touch_cnt * 8);
        //ESP_LOGI(TAG, "[5] d0=%x,d1=%x,d2=%x,d3=%x,d4=%x",buf[0],buf[1],buf[2],buf[3],buf[4]);
		/* Clear all */
		reg_addr[0]=ESP_LCD_TOUCH_GT911_READ_XY_REG>>8;
		reg_addr[1]=ESP_LCD_TOUCH_GT911_READ_XY_REG;
        err = i2c_bus_write_bytes(i2c_handle, GT911_CHIP_ADDR_DEFAULT,reg_addr,sizeof(reg_addr), &clear, 1);
            

        /* Number of touched points */
        tp_num = touch_cnt;
        x = ((uint16_t)buf[3] << 8) + buf[2];
        y = (((uint16_t)buf[5] << 8) + buf[4]);

        btn_val = buf[0] ? 1 : 0;
        btn_signal = (((uint16_t)buf[7] << 8) + buf[6]);

    }   



    return err;
}

esp_err_t gt911_get_touch_point(uint8_t *p_tp_num, uint16_t *p_x, uint16_t *p_y)
{
    *p_x = x;
    *p_y = y;
    *p_tp_num = tp_num;

    return ESP_OK;
}

esp_err_t gt911_get_btn_val(uint8_t *p_btn_val, uint16_t *p_btn_signal)
{
    *p_btn_val = btn_val;
    *p_btn_signal = btn_signal;

    return ESP_OK;
}
